package com.jdd.modules.parkmonthly.service.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jdd.common.constant.JddConstant;
import com.jdd.common.constant.WebSocketToAndAllEnum;
import com.jdd.common.system.vo.LoginUser;
import com.jdd.common.util.BusinessUtils;
import com.jdd.common.util.DateUtils;
import com.jdd.common.util.LoginUserUtils;
import com.jdd.common.util.SnowFlakeUtil;
import com.jdd.modules.parkcar.entity.ParkCarMonthly;
import com.jdd.modules.parkcar.entity.ParkSpace;
import com.jdd.modules.parkcar.service.IParkCarMonthlyService;
import com.jdd.modules.parkcar.service.IParkSpaceService;
import com.jdd.modules.parking.service.IparkCarEnterLogService;
import com.jdd.modules.parkmonthly.entity.MonthlyCarOwner;
import com.jdd.modules.parkmonthly.entity.MonthlyCardEditInfo;
import com.jdd.modules.parkmonthly.entity.MonthlyCardInfo;
import com.jdd.modules.parkmonthly.entity.MonthlyDepartment;
import com.jdd.modules.parkmonthly.entity.MonthlyPackageInfo;
import com.jdd.modules.parkmonthly.entity.PermissionGroup;
import com.jdd.modules.parkmonthly.entity.dto.DownloadMonthlyTempReq;
import com.jdd.modules.parkmonthly.entity.enums.FileType;
import com.jdd.modules.parkmonthly.entity.enums.MonthlyTempKind;
import com.jdd.modules.parkmonthly.entity.vo.ImportExcelErrorInfoVo;
import com.jdd.modules.parkmonthly.entity.vo.MonthlyRemoveRepeatVo;
import com.jdd.modules.parkmonthly.mapper.MonthlyCardInfoMapper;
import com.jdd.modules.parkmonthly.mapper.MonthlyDepartmentMapper;
import com.jdd.modules.parkmonthly.service.IMonthlyCarOwnerService;
import com.jdd.modules.parkmonthly.service.IMonthlyCarTypeConvertService;
import com.jdd.modules.parkmonthly.service.IMonthlyCardEditInfoService;
import com.jdd.modules.parkmonthly.service.IMonthlyCardInfoImportExtService;
import com.jdd.modules.parkmonthly.service.IMonthlyPackageInfoService;
import com.jdd.modules.parkmonthly.service.IPermissionAreaService;
import com.jdd.modules.parkmonthly.service.IPermissionGroupService;
import com.jdd.modules.parkmonthly.util.ExcelReader;
import com.jdd.modules.parkmonthly.util.FileUtil;
import com.jdd.modules.parkmonthly.websocket.MonthlyWebSocket;
import com.jdd.modules.sdkidentifyresultpushlog.service.ISdkIdentifyResultPushLogV3Service;
import com.jdd.modules.shiro.vo.DefContants;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;


/**
 * @Description: 月卡信息表
 * @Author: jdd
 * @Date: 2021-11-09
 * @Version: V1.0
 */
@Service
@Slf4j
@Lazy
public class MonthlyCardInfoImportExtServiceImpl extends ServiceImpl<MonthlyCardInfoMapper, MonthlyCardInfo> implements IMonthlyCardInfoImportExtService {

    @Resource
    private IMonthlyCarTypeConvertService iMonthlyCarTypeConvertService;
    @Resource
    private IMonthlyPackageInfoService iMonthlyPackageInfoService;
    @Resource
    private IMonthlyCardEditInfoService iMonthlyCardEditInfoService;
    @Resource
    private IparkCarEnterLogService iparkCarEnterLogService;
    @Resource
    private IPermissionAreaService iPermissionAreaService;
    @Resource
    private IParkCarMonthlyService iParkCarMonthlyService;
    @Resource
    private IParkSpaceService parkSpaceService;
    @Resource
    private MonthlyCardInfoMapper monthlyCardInfoMapper;
    @Resource
    private IMonthlyCarTypeConvertService monthlyCarTypeConvertService;
    @Resource
    private MonthlyDepartmentMapper monthlyDepartmentMapper;
    @Autowired
    private IPermissionGroupService permissionGroupService;
    @Autowired
    private IMonthlyCarOwnerService monthlyCarOwnerService;
    @Autowired
    @Lazy
    private ISdkIdentifyResultPushLogV3Service sdkIdentifyResultPushLogV3Service;


    @Autowired
    private MonthlyWebSocket monthlyWebSocket;
    @Autowired
    ExecutorService executorService;
    @Autowired
    private DataSource dataSource;
    
    /** 验证月卡套餐是否存在 */
    private MonthlyPackageInfo isPackage(String packageId){
    	return iMonthlyPackageInfoService.getById(packageId);
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public List<ImportExcelErrorInfoVo> verifyImportFile(DownloadMonthlyTempReq req, HttpServletRequest request) throws Exception {
        Long start = System.currentTimeMillis();
        // 验证月租套餐信息是否存在
    	MonthlyPackageInfo info = this.isPackage(req.getPackageId());
    	if(info == null){ throw new Exception("月租套餐不存在，请从新选择"); }
        String token = request.getHeader(DefContants.X_ACCESS_TOKEN);
        MultipartFile file = req.getFile();
        String type = FileUtil.getFileType(file.getInputStream());
        if (!(FileType.XLS_DOC.getValue().equals(type) || FileType.XLSX_DOCX.getValue().equals(type))) {
            throw new Exception("文件格式不正确");
        }
        if (file.isEmpty()) {
            throw new Exception("导入文件不正确");
        }

        List<List<String>> list = ExcelReader.readExcel(file.getInputStream());
        if (list.size() <= 1) {
            throw new Exception("导入文件没有数据");
        }
        Set<String> title = new HashSet<String>(list.get(0));
        // 判断表头必填项是否存在
        String[] must = {MonthlyTempKind.PLATENO_TITLE.value(),
                MonthlyTempKind.STARTTIME_TITLE.value(),
                MonthlyTempKind.ENDTIME_TITLE.value(),
                MonthlyTempKind.OWNERNAME_TITLE.value()};
        for (int x = 0; x < must.length; x++) {
            if (title.add(must[x].toString())) {
                throw new Exception("请下载正确的模板文件");
            }
        }
        // 保存车位信息
        List<String> parkNumbers = new ArrayList<String>();
        // 保存处理后的对象用于导入
        List<ImportExcelErrorInfoVo> importList = new ArrayList<ImportExcelErrorInfoVo>();
        // 验证Excel内容
        if (list != null && list.size() > 0) {
        	// 查询有效的车位信息
        	List<ParkSpace> parkSpaceList = parkSpaceService.getByAreaParkSpace(req.getAreaId(), JddConstant.ParkWhiteListConstant.LICENSE_STATUS_Y);
        	// 未绑定月卡的车位信息
        	List<ParkSpace> unboundParkSpaceList = new ArrayList<ParkSpace>();
        	if (req.getIsAutoPark() != null && req.getIsAutoPark() == 1) {
        		if(CollectionUtils.isEmpty(parkSpaceList)){
        			throw new Exception("区域内没有可用的车位了");
        		}
        		parkSpaceList.forEach(parkSpace->{
        			if(parkSpace.getStartTime() == null){
        				unboundParkSpaceList.add(parkSpace);
        			}
        		});
	        	int countParkNumber = info.getBindingSpaceNumber() * list.size();
	        	// 验证车位是否足够通过套餐所绑定的车位数和Excel条数相乘得到所需要的车位数是否大于未绑定车辆的车位
	        	if(CollectionUtils.isEmpty(unboundParkSpaceList) || countParkNumber > unboundParkSpaceList.size()){
	        		throw new Exception("剩余车位号不够分配了");
	        	}
        	}
        	
            for (int i = 1; i < list.size(); i++) {
                // 组装WebSocket推送数据
                ImportExcelErrorInfoVo vo = this.content(list, i, req, parkNumbers, 
                		parkSpaceList, info.getBindingSpaceNumber(), info, unboundParkSpaceList);
                vo.setNumber(i);
                importList.add(vo);
                if (vo.getIsErrorStr() == 1) {
                    vo = null;
                }
                Map<String, String> map = new HashMap<String, String>(16);
                map.put("data", JSONObject.toJSONString(vo));
                map.put("percentage", String.valueOf(this.percentage(list.size() - 1, i)));
                // 通过WebSocket往前端推送数据
                String message = JSONObject.toJSONString(map);
                JSONObject jo = new JSONObject();
                jo.put("message", message);
                jo.put(WebSocketToAndAllEnum.TO.value(), token);
                log.info("前端推送Excel数据", message);
                monthlyWebSocket.onMessage(JSONObject.toJSONString(jo));
            }
        }
        Long end = System.currentTimeMillis();
        log.info("检验数据用时" + (end - start) / 1000 + "秒");
        return importList;
    }

    /**
     * 计算百分比
     */
    private float percentage(int count, int article) {
        return (100 / (float) count) * article;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public boolean importMonthlyExcel(DownloadMonthlyTempReq req, HttpServletRequest request) throws Exception {
        // 验证需要导入的数据
        List<ImportExcelErrorInfoVo> excelInfo = this.verifyImportFile(req, request);
        if (CollectionUtils.isEmpty(excelInfo)) {
            return false;
        }
        LoginUser user = LoginUserUtils.getLoginUser();
        req.setUserId(user.getId());
        req.setUsername(user.getUsername());
        // 根据月租套餐ID查询月租套餐信息
        MonthlyPackageInfo monthlyPackageInfo = iMonthlyPackageInfoService.getById(req.getPackageId());
        if (monthlyPackageInfo == null) {
            return false;
        }
        req.setPackageName(monthlyPackageInfo.getPackageName());
        req.setCarTypeId(monthlyPackageInfo.getMonthlyTypeId());
        req.setParkName(monthlyPackageInfo.getParkName());

        // 查询部门信息
        MonthlyDepartment dept = monthlyDepartmentMapper.selectById(req.getDeptId());
        if (dept == null) {
            return false;
        }
        req.setDeptName(dept.getDepartName());

        // 查询通行权限信息
        req.setThroughAuthorityName("默认全部权限");
        if(StringUtils.isNotBlank(req.getThroughAuthorityId())){
        	PermissionGroup permissionGroup = permissionGroupService.getById(req.getThroughAuthorityId());
        	if (permissionGroup == null) {
        		return false;
        	}
        	req.setThroughAuthorityName(permissionGroup.getPermissionName());
        }

        // 组装车牌号集合用户判断是否有重复车牌导入
        List<String> plateNoList = new ArrayList<String>();
        // 组装车牌和车位对象集合
        List<ParkCarMonthly> carMonthlyList = new ArrayList<ParkCarMonthly>();
        // 组装新版月卡信息集合数据
        List<MonthlyCardInfo> monthlyCardInfoList = new ArrayList<MonthlyCardInfo>();
        // 组装车主信息集合
        List<MonthlyCarOwner> monthlyCarOwnerList = new ArrayList<MonthlyCarOwner>();
        // 组装月卡操作记录信息集合数据
        List<MonthlyCardEditInfo> monthlyCardEditInfoList = new ArrayList<MonthlyCardEditInfo>();
        // 覆盖导入保存需要删除的月租车ID
        List<String> monthlyIdAllDelList = new ArrayList<String>();
        // 保存已使用的月租编号集合
        List<String> monthlyCodeList = new ArrayList<String>();
        // 需要修改的所有车位信息
        List<ParkSpace> updateAllParkSpaceList = new ArrayList<ParkSpace>();
        for (ImportExcelErrorInfoVo vo : excelInfo) {
            if (vo.getIsErrorStr() == 0) {
                return false;
            }
            List<String> plateNos = vo.getPlateNos();

            // 根据车场编号和车牌号查询车牌和车位关联信息
            List<ParkCarMonthly> carMonthlyDelList = iParkCarMonthlyService.getByPackCodeParkCarMonthlyCount(plateNos);
            if (CollectionUtils.isNotEmpty(carMonthlyDelList)) {
                // 忽略重复
                if (req.getIgnoreOrCover() == 1) {
                    continue;
                }
                // 覆盖导入保存需要删除的月租车信息
                carMonthlyDelList.forEach(carMonthlyDel->{
                	if(!monthlyIdAllDelList.contains(carMonthlyDel.getId())){
                		monthlyIdAllDelList.add(carMonthlyDel.getMonthlyCardId());
                	}
                });
            }
            // 组装月租信息
            MonthlyCardInfo monthlyCardInfo = this.getMonthlyCardInfo(vo, req, monthlyCodeList, user);
            monthlyCodeList.add(monthlyCardInfo.getMonthlyCode());
            monthlyCardInfoList.add(monthlyCardInfo);
            // 组装月卡操作记录信息
            monthlyCardEditInfoList.add(this.getImportMonthlyCardEditInfo(monthlyCardInfo, req, vo, user)
            		.setOverdueDelayWay(monthlyPackageInfo.getOverdueDelayWay()+""));

            // 组装车牌和车位关联关系
            carMonthlyList.addAll(this.getParkCarMonthlyList(
                    plateNos, req, vo, monthlyCardInfo.getId(),
                    plateNoList, carMonthlyList, monthlyCardInfoList, monthlyCarOwnerList,
                    monthlyCardEditInfoList));
            // 装分车主实体类
            monthlyCarOwnerList.add(this.getMonthlyCarOwner(vo, monthlyCardInfo));
            // 保存车牌号用于判断是否有添加车牌
            plateNoList.addAll(this.removeRepeat(plateNos));
            // 组装车位信息用于修改
            List<ParkSpace> upParkSpaceList = vo.getUpParkSpaceList();
            if(CollectionUtils.isNotEmpty(upParkSpaceList)){
            	upParkSpaceList.forEach(parkSpace -> {
            		parkSpace.setMonthlyCardId(monthlyCardInfo.getId());
            		parkSpace.setMonthlyCode(monthlyCardInfo.getMonthlyCode());
            		parkSpace.setStartTime(monthlyCardInfo.getBeginTime());
            		parkSpace.setEndTime(monthlyCardInfo.getEndTime());
            		parkSpace.setUpdateTime(new Date());
            	});
            	updateAllParkSpaceList.addAll(upParkSpaceList);
            }
        }
        boolean flag = false;
        // 保存月租车信息
        if (CollectionUtils.isNotEmpty(monthlyCardInfoList)) {
        	log.info("保存月卡信息总数->{}",monthlyCardInfoList.size());
            flag = this.saveBatch(monthlyCardInfoList);
        }
        // 保存车辆和车位信息
        if (CollectionUtils.isNotEmpty(carMonthlyList)) {
        	log.info("保存车牌和车位关联信息总数->{}",carMonthlyList.size());
        	if(carMonthlyList.size() > 300){
        		CompletableFuture.runAsync(() -> this.saveBatch(carMonthlyList), executorService);
        	}else{
        		iParkCarMonthlyService.saveBatch(carMonthlyList);
        	}
        	/*// 一千条为基准为一个线程处理
            List<List<ParkCarMonthly>> groupList = ListUtils.partition(carMonthlyList, 1000);
            // 保存线程执行返回结果
            List<CompletableFuture<Void>> result = new ArrayList<>();
            groupList.forEach((list)->{
            	CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> iParkCarMonthlyService.saveBatch(list), executorService);
            	result.add(cf);
            });
            // 等待所有线程执行完
            CompletableFuture.allOf(result.toArray(new CompletableFuture[1])).join();*/
        }
        // 保存月租车日志信息
        if (CollectionUtils.isNotEmpty(monthlyCardEditInfoList)) {
        	log.info("保存月卡操作记录信息总数->{}",monthlyCardEditInfoList.size());
            flag = iMonthlyCardEditInfoService.saveBatch(monthlyCardEditInfoList);
        }
        // 保存车主信息
        if (CollectionUtils.isNotEmpty(monthlyCarOwnerList)) {
        	log.info("保存车主信息总数->{}",monthlyCarOwnerList.size());
            flag = monthlyCarOwnerService.saveBatch(monthlyCarOwnerList);
        }
        // 覆盖导入删除月卡信息
        if(CollectionUtils.isNotEmpty(monthlyIdAllDelList)){
        	log.info("删除月卡信息总数->{}",monthlyIdAllDelList.size());
        	flag = this.removeByIds(monthlyIdAllDelList);
        	// 覆盖导入根据月卡ID删除车位和车牌的关联信息
        	LambdaQueryWrapper<ParkCarMonthly> queryWrapper = Wrappers.lambdaQuery();
        	queryWrapper.in(ParkCarMonthly::getMonthlyCardId, monthlyIdAllDelList);
        	iParkCarMonthlyService.remove(queryWrapper);
        	// 更新车位信息
        	LambdaUpdateWrapper<ParkSpace> updateWrapper = Wrappers.lambdaUpdate();
        	updateWrapper.eq(ParkSpace::getParkCode, req.getParkCode());
        	updateWrapper.in(ParkSpace::getMonthlyCardId, monthlyIdAllDelList);
        	updateWrapper.set(ParkSpace::getStartTime, null);
        	updateWrapper.set(ParkSpace::getEndTime, null);
        	updateWrapper.set(ParkSpace::getUserName, null);
        	updateWrapper.set(ParkSpace::getMobile, null);
        	updateWrapper.set(ParkSpace::getAddress, null);
        	updateWrapper.set(ParkSpace::getMonthlyCardId, null);
        	updateWrapper.set(ParkSpace::getMonthlyCode, null);
        	updateWrapper.set(ParkSpace::getPlateNo, null);
        	updateWrapper.set(ParkSpace::getParkStatus, JddConstant.StringNumber.STRING_ZERO);
        	parkSpaceService.update(updateWrapper);
        }
        // 修改车位信息
        if(CollectionUtils.isNotEmpty(updateAllParkSpaceList)){
        	log.info("修改车位信息总数->{}",updateAllParkSpaceList.size());
        	parkSpaceService.updateBatchById(updateAllParkSpaceList);
        }
        return flag;
    }
    
    /** JDBC批处理保存大数据 */
    private void saveBatch(List<ParkCarMonthly> list){
    	Connection conn = null;
    	PreparedStatement preparedStatement = null;
    	String sql = "";
    	try {
    		conn = dataSource.getConnection();
			// 手动提交事务
			conn.setAutoCommit(false);
			sql = "INSERT INTO park_car_monthly VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
			preparedStatement = conn.prepareStatement(sql);
			long begin = System.currentTimeMillis();
			for(int i = 0; i < list.size(); i++){
				preparedStatement.setString(1, list.get(i).getId());
				preparedStatement.setString(2, list.get(i).getPlateNo());
				preparedStatement.setString(3, list.get(i).getParkCode());
				preparedStatement.setString(4, list.get(i).getParkName());
				preparedStatement.setString(5, list.get(i).getAreaId());
				preparedStatement.setString(6, list.get(i).getAreaName());
				preparedStatement.setDate(7, list.get(i).getStartTime() == null ? null : new java.sql.Date(list.get(i).getStartTime().getTime()));
				preparedStatement.setDate(8, list.get(i).getEndTime() == null ? null : new java.sql.Date(list.get(i).getEndTime().getTime()));
				preparedStatement.setString(9, list.get(i).getStatus());
				preparedStatement.setString(10, list.get(i).getCarTypeId());
				preparedStatement.setString(11, list.get(i).getUserName());
				preparedStatement.setString(12, list.get(i).getMobile());
				preparedStatement.setString(13, list.get(i).getParkNumber());
				preparedStatement.setString(14, list.get(i).getIsMulti());
				preparedStatement.setString(15, list.get(i).getPayFee() == null ? null : list.get(i).getPayFee().toString());
				preparedStatement.setString(16, list.get(i).getAddress());
				preparedStatement.setDate(17, list.get(i).getCreateTime() == null ? null : new java.sql.Date(list.get(i).getCreateTime().getTime()));
				preparedStatement.setDate(18, list.get(i).getUpdateTime() == null ? null : new java.sql.Date(list.get(i).getUpdateTime().getTime()));
				preparedStatement.setString(19, list.get(i).getCreateUser());
				preparedStatement.setString(20, list.get(i).getRemark());
				preparedStatement.setString(21, list.get(i).getMonthlyCardId());
				preparedStatement.setString(22, list.get(i).getDelFlag());
				// 积攒sql
				preparedStatement.addBatch();
				// 积攒到一定程度，就统一一次提交，并清空已提交的sql
				if((i+1) % 300 == 0){
					preparedStatement.executeBatch();
					preparedStatement.clearBatch();
				}
			}
			// 若总条数不是批量数值的整数，则需要再额外的执行一次
			if(list.size() % 300 != 0){
				preparedStatement.executeBatch();
				preparedStatement.clearBatch();
			}
			long end = System.currentTimeMillis();
			log.info("用时-> {} 秒",(end - begin) / 1000);
			conn.commit();
		} catch (SQLException e) {
			e.printStackTrace();
			this.rollback(conn);
		} finally {
			this.release(conn, preparedStatement);
		}
    }
    
    /** 回滚 */
    private void rollback(Connection connection) {
    	if(connection != null){
			try {
				connection.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
		}
    }
    
    /** 关闭数据库操作对象、数据库连接 */
    private void release(Connection connection, PreparedStatement preparedStatement) {

        if(preparedStatement!=null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(connection!=null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 组装车主信息
     */
    private MonthlyCarOwner getMonthlyCarOwner(ImportExcelErrorInfoVo vo, MonthlyCardInfo monthlyCardInfo) {
        MonthlyCarOwner entity = new MonthlyCarOwner();
        entity.setId(SnowFlakeUtil.getId());
        entity.setAddress(vo.getRoomNumber());
        entity.setCarOwnerName(vo.getOwnerName());
        entity.setMonthlyDepartmentId(monthlyCardInfo.getMonthlyDepartmentId());
        entity.setMonthlyDepartmentName(monthlyCardInfo.getMonthlyDepartmentName());
        entity.setTelephone(vo.getPhoneNumber());
        entity.setCreateUserId(monthlyCardInfo.getCreateUserId());
        entity.setCreateUserName(monthlyCardInfo.getCreateUserName());
        entity.setCreateTime(new Date());
        return entity;
    }

    /**
     * 组装月卡信息
     */
    private MonthlyCardInfo getMonthlyCardInfo(ImportExcelErrorInfoVo vo, 
    		DownloadMonthlyTempReq req, List<String> monthlyCodeList,LoginUser user) {
        MonthlyCardInfo entity = new MonthlyCardInfo();
        entity.setId(SnowFlakeUtil.getId());
        entity.setParkCode(req.getParkCode());
        entity.setParkName(req.getParkName());
        entity.setPackageId(req.getPackageId());
        entity.setPackageName(req.getPackageName());
        entity.setCarOwnerName(vo.getOwnerName());
        entity.setMonthlyDepartmentId(req.getDeptId());
        entity.setMonthlyDepartmentName(req.getDeptName());
        entity.setThroughAuthorityId(req.getThroughAuthorityId());
        entity.setThroughAuthorityName(req.getThroughAuthorityName());
        entity.setAddress(vo.getRoomNumber());
        entity.setTelephone(vo.getPhoneNumber());
        entity.setBeginTime(DateUtil.parse(vo.getStartTime() + " 00:00:00"));
        entity.setEndTime(DateUtil.parse(vo.getEndTime() + " 23:59:59"));
        entity.setDelFlag(JddConstant.IntNumber.INT_ZERO);
        entity.setCreateUserId(user.getUsername());
        entity.setCreateUserName(user.getRealname());
        entity.setCreateTime(new Date());
        entity.setMonthlyStatus(JddConstant.IntNumber.INT_ONE);
        entity.setMonthlyCode(this.getMonthlyCode(req.getParkCode(), monthlyCodeList));
        return entity;
    }
    
    /**
     * 月卡编号生成规则
     *
     * @param parkCode
     * @return
     */
    public String getMonthlyCode(String parkCode,List<String> monthlyCodeList) {
        String monthlyCode;
        QueryWrapper<MonthlyCardInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("park_code", parkCode);
        List<MonthlyCardInfo> monthlyCardInfoList = this.list(queryWrapper);
        // 如果月卡信息为空并且导入信息为空
        if (CollectionUtil.isEmpty(monthlyCardInfoList) && CollectionUtils.isEmpty(monthlyCodeList)) {
            return "P000" + 1;
        }
        // 如果传入的List不为空则根据下标获取最后一条信息
        if(CollectionUtils.isNotEmpty(monthlyCodeList)){
        	monthlyCode = monthlyCodeList.get(monthlyCodeList.size() - 1);
        }else{
        	List<MonthlyCardInfo> monthlyCardInfos = monthlyCardInfoList.stream()
        			.sorted(Comparator.comparing(MonthlyCardInfo::getMonthlyCode).reversed())
        			.collect(Collectors.toList());
        	monthlyCode = monthlyCardInfos.get(0).getMonthlyCode();
        }
        int num = Integer.parseInt(monthlyCode.substring(1));
        num++;
        if (num < 10) {
            monthlyCode = "P000" + num;
        } else if (num >= 10 && num < 100) {
            monthlyCode = "P00" + num;
        } else if (num >= 100 && num < 1000) {
            monthlyCode = "P0" + num;
        } else if (num >= 1000 && num < 10000) {
            monthlyCode = "P" + num;
        } else {
        }
        log.info("生成的新的月卡编号为-------------》:{}", monthlyCode);
        return monthlyCode;
    }

    /**
     * 组装月卡操作记录信息
     */
    private MonthlyCardEditInfo getImportMonthlyCardEditInfo(
            MonthlyCardInfo monthlyCardInfo, DownloadMonthlyTempReq req, 
            ImportExcelErrorInfoVo vo, LoginUser user) {
        MonthlyCardEditInfo entity = new MonthlyCardEditInfo();
        BeanUtils.copyProperties(monthlyCardInfo, entity);
        entity.setId(SnowFlakeUtil.getId());
        entity.setOptionsType(JddConstant.StringNumber.STRING_EIGHT);
        BigDecimal decimal = new BigDecimal(vo.getMoney());
        // 小数位后两位直接舍弃
        decimal.setScale(2, BigDecimal.ROUND_DOWN);
        entity.setPayTheFee(decimal);
        entity.setMonthlyCardId(monthlyCardInfo.getId());
        entity.setUserName(vo.getOwnerName());
        entity.setPlateNos(vo.getPlateNo());
        entity.setParkNumbers(vo.getParkNumbers());
        entity.setStartTime(monthlyCardInfo.getBeginTime());
        entity.setEndTime(monthlyCardInfo.getEndTime());
        entity.setBusinessSource(JddConstant.StringNumber.STRING_ONE);
        entity.setCreateUserId(user.getUsername());
        entity.setCreateUserName(user.getRealname());
        return entity;
    }

    /**
     * 组装车位和车牌信息集合
     */
    private List<ParkCarMonthly> getParkCarMonthlyList(List<String> plateNos, DownloadMonthlyTempReq req,
                                                       ImportExcelErrorInfoVo vo, String monthlyCardId,
                                                       List<String> plateNoAllList, List<ParkCarMonthly> carMonthlyList,
                                                       List<MonthlyCardInfo> monthlyCardInfoList, List<MonthlyCarOwner> monthlyCarOwnerList,
                                                       List<MonthlyCardEditInfo> monthlyCardEditInfoList) {

        List<ParkCarMonthly> list = new ArrayList<ParkCarMonthly>();
        // 获取去重后的车牌号集合
        List<String> plateNoList = this.removeRepeat(plateNos);
        // 获取去重后的车位集合
        List<ParkSpace> parkSpaceList = vo.getUpParkSpaceList();
        //List<String> parkNumberList = new ArrayList<String>();
        List<ParkSpace> parkNumberList = new ArrayList<ParkSpace>();
        for(ParkSpace parkSpace : parkSpaceList){
        	if(parkNumberList.size() < 1){
        		parkNumberList.add(parkSpace);
        	}else if(!parkNumberList.contains(parkSpace.getParkNumber())){
        		parkNumberList.add(parkSpace);
        	}
        }

        // 组装车位和车牌关联实体类
        for (String plateNo : plateNoList) {

            // 文件中有重复车牌
            if (plateNoAllList.contains(plateNo)) {
                // 判断重复车牌是忽略重复还是覆盖导入,如果是忽略重复直接返回不处理，如果是覆盖导入则修改老数据
                if (req.getIgnoreOrCover() == 1) {
                    // 直接返回
                    return new ArrayList<ParkCarMonthly>();
                }
                this.monthlyRemoveRepeat(carMonthlyList, monthlyCardInfoList, monthlyCarOwnerList, monthlyCardEditInfoList, plateNo, vo.getOwnerName());
            }

            for (ParkSpace parkNumber : parkNumberList) {
                ParkCarMonthly entity = new ParkCarMonthly();
                entity.setId(SnowFlakeUtil.getId());
                entity.setParkCode(req.getParkCode());
                entity.setParkName(req.getParkName());
                entity.setAreaId(parkNumber.getAreaId());
                entity.setStartTime(DateUtil.parse(vo.getStartTime() + " 00:00:00"));
                entity.setEndTime(DateUtil.parse(vo.getEndTime() + " 23:59:59"));
                entity.setStatus(JddConstant.ParkWhiteListConstant.LICENSE_STATUS_Y);
                entity.setCarTypeId(req.getCarTypeId());
                entity.setParkNumber(parkNumber.getParkNumber());
                entity.setPlateNo(plateNo);
                entity.setCreateTime(new Date());
                entity.setCreateUser(req.getUsername());
                entity.setMonthlyCardId(monthlyCardId);
                entity.setMobile(vo.getPhoneNumber());
                entity.setDelFlag(String.valueOf(JddConstant.IntNumber.INT_ZERO));
                list.add(entity);
            }
        }
        return list;
    }

    /**
     * 去除重复月卡关联数据
     */
    private MonthlyRemoveRepeatVo monthlyRemoveRepeat(List<ParkCarMonthly> carMonthlyList,
                                                      List<MonthlyCardInfo> monthlyCardInfoList, List<MonthlyCarOwner> monthlyCarOwnerList,
                                                      List<MonthlyCardEditInfo> monthlyCardEditInfoList, String plateNo, String name) {
        MonthlyRemoveRepeatVo vo = new MonthlyRemoveRepeatVo();
        ParkCarMonthly entity = new ParkCarMonthly();
        // 覆盖导入修改之前重复的数据
        for (ParkCarMonthly parkCarMonthly : carMonthlyList) {
            if (plateNo.equals(parkCarMonthly.getPlateNo())) {
                entity = parkCarMonthly;
                break;
            }
        }
        carMonthlyList.remove(entity);

        if (StringUtils.isNotBlank(entity.getMonthlyCardId())) {
            // 去除重复的月卡信息
            MonthlyCardInfo repeatMonthlyCardInfo = new MonthlyCardInfo();
            for (MonthlyCardInfo monthlyCardInfo : monthlyCardInfoList) {
                if (entity.getMonthlyCardId().equals(monthlyCardInfo.getId())) {
                    repeatMonthlyCardInfo = monthlyCardInfo;
                    break;
                }
            }
            monthlyCardInfoList.remove(repeatMonthlyCardInfo);

            // 去除重复的月卡日志信息
            MonthlyCardEditInfo repeatMonthlyCardEditInfo = new MonthlyCardEditInfo();
            for (MonthlyCardEditInfo monthlyCardEditInfo : monthlyCardEditInfoList) {
                if (entity.getMonthlyCardId().equals(monthlyCardEditInfo.getMonthlyCardId())) {
                    repeatMonthlyCardEditInfo = monthlyCardEditInfo;
                    break;
                }
            }
            monthlyCardEditInfoList.remove(repeatMonthlyCardEditInfo);

            // 去除车主信息
            MonthlyCarOwner repeatMonthlyCarOwner = new MonthlyCarOwner();
            if (StringUtils.isNotBlank(name)) {
                for (MonthlyCarOwner monthlyCarOwner : monthlyCarOwnerList) {
                    if (name.equals(monthlyCarOwner.getCarOwnerName())) {
                        repeatMonthlyCarOwner = monthlyCarOwner;
                        break;
                    }
                }
                monthlyCarOwnerList.remove(repeatMonthlyCarOwner);
            }
        }
        vo.setCarMonthlyList(carMonthlyList);
        vo.setMonthlyCardEditInfoList(monthlyCardEditInfoList);
        vo.setMonthlyCardInfoList(monthlyCardInfoList);
        vo.setMonthlyCarOwnerList(monthlyCarOwnerList);
        return vo;
    }

    /**
     * 去重
     */
    private List<String> removeRepeat(List<String> array) {
        return array.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 验证传入的Excel单行数据
     */
    private ImportExcelErrorInfoVo content(List<List<String>> list, int i, 
    		DownloadMonthlyTempReq req, List<String> parkNumbers,
    		List<ParkSpace> parkSpaceList,Integer bindingSpaceNumber,
    		MonthlyPackageInfo info,List<ParkSpace> unboundParkSpaceList) {
        ImportExcelErrorInfoVo vo = new ImportExcelErrorInfoVo();
        vo.setIsErrorStr(1);
        // 保存开始时间
        String startTime = "";
        // 保存单行错误信息多个用,隔开
        StringBuilder errorInfo = new StringBuilder();
        for (int j = 0; j < list.get(i).size(); j++) {
            String value = list.get(i).get(j);
            switch (j) {
                case 0:
                    // 车牌号
                    if (StringUtils.isBlank(value)) {
                        errorInfo.append("车牌号不能为空").append(",");
                        break;
                    }
                    vo.setPlateNo(value);
                    StringBuilder plateNoBuf = new StringBuilder();
                    String[] plateNos = value.split(",");
                    // 实际导入车牌号大于月租套餐可绑定车牌数给出提示
                    if(plateNos.length > info.getBindingCarNumber()){
                    	errorInfo.append("导入车牌数不能多于套餐可绑定车牌数").append(",");
                    	break;
                    }
                    //vo.setPlateNos(plateNos);
                    List<String> plateNoList = new ArrayList<String>();
                    // 车牌号下标
                    int plateNoIndex = 0;
                    for (String plateNo : plateNos) {
                        if (!BusinessUtils.checkVehicleNum(plateNo.trim())) {
                            errorInfo.append(plateNo + "车牌号不正确").append(",");
                        }
                        if(plateNoIndex < 99){
                        	plateNoBuf.append(plateNo.trim()).append(",");
                        }
                        if(plateNoIndex == 99){
                        	plateNoBuf.append("...");
                        }
                        plateNoList.add(plateNo.trim());
                        plateNoIndex ++;
                    }
                    vo.setPlateNos(plateNoList);
                    if(StringUtils.isNotBlank(plateNoBuf.toString())){
                    	vo.setPlateNo(plateNoBuf.substring(0,plateNoBuf.length()-1).toString());
                    }
                    break;
                case 1:
                	// 自动分配月租车位
                	StringBuilder buf = new StringBuilder();
                	// 组装要修改的车位信息
                	List<ParkSpace> upParkSpaceList = new ArrayList<ParkSpace>();
                	// 车位号下表
                    int parkNumberIndex = 0;
                    if (req.getIsAutoPark() != null && req.getIsAutoPark() == 1) {
                    	// 保存拼接后的车位信息
                    	for(int n = 0; n < bindingSpaceNumber; n ++){
                    		if(parkNumberIndex < 99){
                    			buf.append(unboundParkSpaceList.get(n).getParkNumber()).append(",");
                    		}
                    		if(parkNumberIndex == 99){
                    			buf.append("...");
                            }
                    		parkNumberIndex ++;
                    		upParkSpaceList.add(unboundParkSpaceList.get(n));
                    	}
                        // 清除已绑定的车位
                    	unboundParkSpaceList.removeAll(upParkSpaceList);
                    }else{
                    	if (StringUtils.isBlank(value)) {
                            errorInfo.append("车位不能为空").append(",");
                            break;
                        }
                    	vo.setParkNumbers(value);
                    	String[] parkNumberArray = value.split(",");
                    	// 实际导入车位大于月租套餐可绑定车位数给出提示
                        if(parkNumberArray.length != info.getBindingSpaceNumber()){
                        	errorInfo.append("导入车位数据和套餐可绑定车位数不匹配").append(",");
                        	break;
                        }
                    	for(String parkNumber : parkNumberArray){
                    		if(StringUtils.isNotBlank(parkNumber.trim())){
                    			// List<ParkSpace> lists = this.getIsParkCode(req.getAreaId(), parkNumber.trim());
                    			// 是否存在车位号，默认不存在
                    			boolean isParkNumber = false;
                    			// 车位是否绑定月卡，默认未绑定
                    			boolean isMonthly = false;
                    			for(ParkSpace parkSpace : parkSpaceList){
                    				if(parkNumber.trim().equals(parkSpace.getParkNumber())){
                    					// 车位存在
                    					upParkSpaceList.add(parkSpace);
                    					isParkNumber = true;
                    					// 判断车位是否绑定月卡
                    					if(parkSpace.getStartTime() != null){
                    						isMonthly = true;
                    					}
                    					break;
                    				}
                    			}
                    			if(!isParkNumber){
                    				errorInfo.append(parkNumber.trim() + "车位不存在，请先添加车位").append(",");
                    			}else if(isMonthly){
                    				errorInfo.append(parkNumber.trim() + "车位已绑定车牌号，请重新绑定").append(",");
                    			}
                    			parkNumbers.add(parkNumber.trim());
                    			
                    			if(parkNumberIndex < 99){
                    				buf.append(parkNumber.trim()).append(",");
                    			}
                    			if(parkNumberIndex == 99){
                        			buf.append("...");
                                }
                    			parkNumberIndex++;
                    		}
                    	}
                    }
                    if(CollectionUtils.isNotEmpty(upParkSpaceList)){
                    	vo.setUpParkSpaceList(upParkSpaceList);
                    }
                    if(StringUtils.isNotBlank(buf.toString())){
                    	vo.setParkNumbers(buf.substring(0,buf.length()-1).toString());
                    }
                    break;
                case 2:
                    // 起始时间
                    vo.setStartTime(value);
                    if (StringUtils.isBlank(value)) {
                        errorInfo.append("起始时间不能为空").append(",");
                    } else if (!BusinessUtils.isDate(value)) {
                        errorInfo.append("起始时间格式不正确，例如：2021-11-11").append(",");
                    } else {
                        startTime = value;
                    }
                    break;
                case 3:
                    // 到期时间
                    vo.setEndTime(value);
                    if (StringUtils.isBlank(value)) {
                        errorInfo.append("到期时间不能为空").append(",");
                    } else if (!BusinessUtils.isDate(value)) {
                        errorInfo.append("到期时间格式不正确，例如：2021-11-11").append(",");
                    } else {
                        try {
                        	if (StringUtils.isNotBlank(startTime) && DateUtils.dateDiff('s',
                            		DateUtil.parse(value + " 23:59:59").toCalendar(),
                                    DateUtil.parse(startTime + " 00:00:00").toCalendar()) < 0) {
                                errorInfo.append("起始时间不能大于到期时间").append(",");
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                    break;
                case 4:
                    // 金额
                    vo.setMoney(value);
                    if(StringUtils.isBlank(value)){
                    	errorInfo.append("金额不能为空").append(",");
                    	break;
                    }
                    if (!BusinessUtils.isMoney(value)) {
                        errorInfo.append("金额不正确").append(",");
                    }
                    break;
                case 5:
                    // 车主姓名
                    vo.setOwnerName(value);
                    if (StringUtils.isBlank(value)) {
                        errorInfo.append("车主姓名不能为空").append(",");
                    }
                    break;
                case 6:
                    // 手机号码
                    vo.setPhoneNumber(value);
                    if (StringUtils.isNotBlank(value) && !BusinessUtils.isNumeric(value)) {
                        errorInfo.append("手机号格式不正确").append(",");
                    }
                    break;
                case 7:
                    // 住房/房号
                    vo.setRoomNumber(value);
                    break;
            }
        }
        if (StringUtils.isNotBlank(errorInfo)) {
            String str = errorInfo.substring(0, errorInfo.length() - 1);
            vo.setIsErrorStr(0);
            vo.setRemarks(str);
        }
        return vo;
    }

}
